package com.sec.android.app.myfiles.activity;

import android.app.ActionBar;
import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.Settings;
import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.DigitsKeyListener;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.Window;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;

import com.sec.android.app.myfiles.R;
import com.sec.android.app.myfiles.log.Log;
import com.sec.android.app.myfiles.util.UiUtils;

import java.lang.ref.WeakReference;

public class ChangePasswordsActivity extends Activity implements OnClickListener, OnEditorActionListener, TextWatcher, OnFocusChangeListener {
    private Button mCancelButton;
    private Button mNextButton;
    private TextView mPasswordEntry;
    private TextView mHeaderText;

    private InputMethodManager mInputMethodManager;

    private boolean keyboardVisibleBK;
    private boolean keyboardVisible;
    private String mFirstPin;
    private boolean isChangePW;

    private static final String PREFS = "AppLockPreferences";
    private static final String PRESS_CANCEL = "press_cancel";
    public static final String APP_LOCK_ENABLE = "applock_enable";
    private static final String PREF_APP_LOCK_PIN = "PREF_APPLOCK_PIN";
    private static final String CHANGE_PIN = "change_pin";
    private static final String KEY_FIRST_PIN = "first_pin";
    private static final String KEY_UI_STAGE = "ui_stage";

    private static final long ERROR_MESSAGE_TIMEOUT = 1000;

    private static final int sPasswordMinLength = 4;
    private static final int sPasswordMaxLength = 16;

    private static final int HIDE_KEYBOARD = 0;
    private static final int INPUT_KEYBOARD = 1;

    private boolean isConfigurationChanged = false;

    private Stage mUiStage = Stage.Introduction;

    private static Handler mHandler = new Handler();
    private Handler mTimingHandler = new WeakRefHandler(this);

    protected enum Stage {
        Introduction(R.string.lockpassword_choose_your_pin_header, R.string.lockpassword_continue_label),
        NeedToConfirm(R.string.lockpassword_confirm_your_pin_header, R.string.ok),
        ConfirmWrong(R.string.lockpassword_confirm_pins_dont_match, R.string.ok);

        Stage(int hintInNumeric, int nextButtonText) {
            this.numericHint = hintInNumeric;
            this.buttonText = nextButtonText;
        }

        public final int numericHint;
        public final int buttonText;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
        super.onCreate(savedInstanceState);

        UiUtils.setWindowAttribute(this, null);
        initViews();
        isChangePW = isChangePassword();

        if (Settings.System.getInt(this.getContentResolver(), APP_LOCK_ENABLE, 0) != 0 && !isChangePW) { // memo direct click
            updateStage(Stage.NeedToConfirm);
            mFirstPin = Settings.System.getString(this.getContentResolver(), PREF_APP_LOCK_PIN);
        } else if (Settings.System.getInt(this.getContentResolver(), APP_LOCK_ENABLE, 0) != 0 && isChangePW) {
            updateStage(Stage.NeedToConfirm);
            mFirstPin = Settings.System.getString(this.getContentResolver(), PREF_APP_LOCK_PIN);

        } else {
            updateStage(Stage.Introduction);
        }

        // ?
        mTimingHandler.sendMessageDelayed(mTimingHandler.obtainMessage(INPUT_KEYBOARD, this), 250);
    }

    @Override
    protected void onResume() {
        super.onResume();
        updateStage(mUiStage);

        sipProcess();
    }

    private void sipProcess() {
        KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
        if (km.inKeyguardRestrictedInputMode()) {
            mTimingHandler.sendMessageDelayed(mTimingHandler.obtainMessage(HIDE_KEYBOARD, this), 0);
            keyboardVisibleBK = keyboardVisible = false;
        } else if (mPasswordEntry.isFocusable()) {
            mTimingHandler.sendMessageDelayed(mTimingHandler.obtainMessage(INPUT_KEYBOARD, this), 500);
            keyboardVisibleBK = keyboardVisible = true;
        } else if (keyboardVisibleBK) {
            mPasswordEntry.requestFocus();
            mTimingHandler.sendMessageDelayed(mTimingHandler.obtainMessage(INPUT_KEYBOARD, this), 500);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        keyboardVisibleBK = keyboardVisible;
        if (keyboardVisibleBK)
            mTimingHandler.sendMessage(mTimingHandler.obtainMessage(HIDE_KEYBOARD, this));
    }

    private void initViews() {
        setContentView(R.layout.change_lock_password);
        ActionBar actionBar = getActionBar();
        if (actionBar != null) {
            actionBar.setDisplayShowTitleEnabled(true);
            actionBar.setDisplayShowHomeEnabled(false);
            // actionBar.setDisplayUseLogoEnabled(true);
            // actionBar.setDisplayHomeAsUpEnabled(true);
            actionBar.setTitle(R.string.passcode_lock);
        }

        mCancelButton = (Button) findViewById(R.id.cancel_button);
        mCancelButton.setOnClickListener(this);
        mNextButton = (Button) findViewById(R.id.next_button);
        mNextButton.setOnClickListener(this);

        mPasswordEntry = (TextView) findViewById(R.id.password_entry);
        mPasswordEntry.setOnEditorActionListener(this);
        mPasswordEntry.addTextChangedListener(this);

        mPasswordEntry.setFilters(new InputFilter[]{
                new InputFilter.LengthFilter(sPasswordMaxLength)});
        mPasswordEntry.setKeyListener(DigitsKeyListener.getInstance());
        mPasswordEntry.setImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
        mPasswordEntry.setPrivateImeOptions("inputType=YearDateTime_edittext");

        // Voice input not required in case of password window.
        mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);

        mPasswordEntry.setOnFocusChangeListener(this);
        mPasswordEntry.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                // TODO Auto-generated method stub
            }
        });

        mPasswordEntry.setLongClickable(false);
        mHeaderText = (TextView) findViewById(R.id.headerText);

        mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
        keyboardVisibleBK = false;
    }

    @Override
    public void onFocusChange(View arg0, boolean isFocused) {
        if (!isFocused) {
            hideKeyboard();
        }
    }

    @Override
    protected void onDestroy() {

        hideKeyboard();
        super.onDestroy();
        finish();
        // MyFilesLog.v(MyFilesLog.LOG_LEVEL_LOW, MODULE, "onDestroy");
        // Log.v(TAG, "onDestroy");
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(KEY_UI_STAGE, mUiStage.name());
        outState.putString(KEY_FIRST_PIN, mFirstPin);

        // P121115-5574 PIN do not match msg is shown when user change font size
        // during confirming new pin.
        if (mUiStage == Stage.NeedToConfirm) {
            if (Settings.System.getInt(this.getContentResolver(), APP_LOCK_ENABLE, 0) == 0) {
                Settings.System.putInt(this.getContentResolver(), APP_LOCK_ENABLE, 1);
            }
            try {
                Settings.System.putString(this.getContentResolver(), PREF_APP_LOCK_PIN, mFirstPin);
            } catch (Exception e) {
                Log.e(this, "Exception:" + e.toString());
            }
        }
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        String state = savedInstanceState.getString(KEY_UI_STAGE);
        mFirstPin = savedInstanceState.getString(KEY_FIRST_PIN);
        if (state != null) {
            mUiStage = Stage.valueOf(state);
            updateStage(mUiStage);
        }
    }

    @Override
    public void onConfigurationChanged(Configuration arg0) {
        isConfigurationChanged = true;
        String lockCode = mPasswordEntry.getText().toString();
        initViews();
        mPasswordEntry.setText(lockCode);
        if (mPasswordEntry.isFocusable() || mPasswordEntry.isFocused()) {
            sipProcess();
        }
        updateUi();
        isConfigurationChanged = false;
        super.onConfigurationChanged(arg0);
        UiUtils.setWindowAttribute(this, null);
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        switch (v.getId()) {
            case R.id.next_button:
                handleNext();
                break;
            case R.id.cancel_button:
                doCancel();
                break;
            default:
                break;
        }

    }

    @Override
    public void onBackPressed() {
        super.onBackPressed();
        doCancel();
    }

    private void doCancel() {
        setResult(RESULT_CANCELED);
        SharedPreferences mSharedPreferences = getSharedPreferences(PREFS, Activity.MODE_PRIVATE);
        SharedPreferences.Editor editor = mSharedPreferences.edit();
        editor.putInt(PRESS_CANCEL, 1);
        editor.apply();
        mTimingHandler.sendMessageDelayed(mTimingHandler.obtainMessage(HIDE_KEYBOARD, this), 0);
        finish();
    }

    private void handleNext() {
        final String pin = mPasswordEntry.getText().toString();
        if (TextUtils.isEmpty(pin)) {
            return;
        }
        String errorMsg = null;

        if (mUiStage == Stage.Introduction) {
            errorMsg = validatePassword(pin);
            if (errorMsg == null) {
                mFirstPin = pin;
                updateStage(Stage.NeedToConfirm);
                mPasswordEntry.setText("");
            }
        } else if (mUiStage == Stage.NeedToConfirm) {
            if (mFirstPin.equals(pin)) { // confirmed pw
                if (isChangePW) { // change pw
                    updateStage(Stage.Introduction);
                    mPasswordEntry.setText("");
                    isChangePW = false;
                } else {
                    try {
                        Settings.System.putString(this.getContentResolver(), PREF_APP_LOCK_PIN, mFirstPin);
                        Settings.System.putInt(this.getContentResolver(), APP_LOCK_ENABLE, 1);
                    } catch (Exception e) {
                        Log.e(this, "Exception:" + e.toString());
                    }
                    Intent intent = new Intent();
                    setResult(RESULT_OK, intent);
                    mTimingHandler.sendMessageDelayed(mTimingHandler.obtainMessage(HIDE_KEYBOARD, this), 0);
                    finish();
                }

            } else {
                updateStage(Stage.ConfirmWrong);
                mPasswordEntry.setText("");
            }
        }
        if (errorMsg != null) {
            showError(errorMsg, mUiStage);
        }
    }

    private void showError(String msg, final Stage next) {
        mHeaderText.setText(msg);
        mHandler.postDelayed(new Runnable() {
            public void run() {
                updateStage(next);
            }
        }, ERROR_MESSAGE_TIMEOUT);
    }

    private String validatePassword(String password) {
        if (password.length() < sPasswordMinLength) {
            return getString(R.string.lockpassword_pin_too_short, sPasswordMinLength);
        }
        if (password.length() > sPasswordMaxLength) {
            return getString(R.string.lockpassword_pin_too_long, sPasswordMaxLength);
        }

        for (int i = 0; i < password.length(); i++) {
            char c = password.charAt(i);

            if (!Character.isDigit(c)) {
                return getString(R.string.lockpassword_pin_contains_non_digits);
            }
        }

        return null;

    }

    public boolean onOptionsItemSelected(MenuItem item) {
        Log.a(this, "onOptionsItemSelected [" + item.getTitle() + "]");

        switch (item.getItemId()) {
            case android.R.id.home:
                SharedPreferences mSharedPreferences = getSharedPreferences(PREFS, Activity.MODE_PRIVATE);
                SharedPreferences.Editor editor = mSharedPreferences.edit();
                editor.putInt(PRESS_CANCEL, 1);
                editor.apply();

                mTimingHandler.sendMessageDelayed(mTimingHandler.obtainMessage(HIDE_KEYBOARD, this), 0);
                finish();
                break;
        }
        return true;
    }

    public boolean onKeyDown(int keyCode, KeyEvent keyEvent) {
        if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
            String password = mPasswordEntry.getText().toString();
            final int length = password.length();
            if (length == 0) {
                mNextButton.setFocusable(false);
            }
        }

        return super.onKeyDown(keyCode, keyEvent);
    }

    private void updateStage(Stage stage) {
        mUiStage = stage;
        updateUi();
    }

    private void updateUi() {
        String password = mPasswordEntry.getText().toString();
        final int length = password.length();

        if (mUiStage == Stage.Introduction && length > 0) {
            if (length < sPasswordMinLength) {
                String msg = getString(R.string.lockpassword_pin_too_short, sPasswordMinLength);
                mHeaderText.setText(msg);
                mNextButton.setEnabled(false);
                mNextButton.setFocusable(false);
            } else {
                String error = validatePassword(password);
                if (error != null) {
                    mHeaderText.setText(error);
                    mNextButton.setEnabled(false);
                    mNextButton.setFocusable(false);
                } else {
                    mHeaderText.setText(R.string.lockpassword_press_continue);
                    // }
                    mNextButton.setEnabled(true);
                    mNextButton.setFocusable(true);
                }
            }
        } else {
            mHeaderText.setText(mUiStage.numericHint);
            mNextButton.setEnabled(length > 0);
            mNextButton.setFocusable(true);
        }
        mPasswordEntry.requestFocus();
        mNextButton.setText(mUiStage.buttonText);
    }

    @Override
    public void afterTextChanged(Editable s) {
        // TODO Auto-generated method stub

        if (mUiStage == Stage.ConfirmWrong) {
            mUiStage = Stage.NeedToConfirm;
            new Handler().postDelayed(new Runnable() {
                public void run() {
                    mHeaderText.setText(R.string.lockpassword_confirm_your_pin_header);
                }
            }, ERROR_MESSAGE_TIMEOUT * 3);

            if (s.toString().isEmpty()) {
                mNextButton.setEnabled(false);
                return;
            }
        }
        updateUi();
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        // TODO Auto-generated method stub

        Editable edit = (Editable) mPasswordEntry.getText();
        String strToastMsg;
        if (edit.length() >= sPasswordMaxLength && !isConfigurationChanged) {
            strToastMsg = String.format(this.getText(R.string.lockpassword_pin_too_long).toString(), sPasswordMaxLength);
            Toast.makeText(this, strToastMsg, Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
        // TODO Auto-generated method stub
        if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE || actionId == EditorInfo.IME_ACTION_NEXT) {
            handleNext();
            return true;
        }
        return false;
    }

    private static class WeakRefHandler extends Handler {
        WeakReference<ChangePasswordsActivity> mUpdateActivity = null;

        WeakRefHandler(ChangePasswordsActivity activity) {
            mUpdateActivity = new WeakReference<>(activity);
        }

        public void handleMessage(Message msg) {
            ChangePasswordsActivity activity = mUpdateActivity.get();
            if (activity != null) {
                switch (msg.what) {
                    case HIDE_KEYBOARD:
                        activity.hideKeyboard();
                        break;
                    case INPUT_KEYBOARD:
                        activity.showKeyboard();
                        break;
                }
            }
        }
    }

    private void showKeyboard() {
        //TODO HYL
    }

    private void hideKeyboard() {
        mInputMethodManager.hideSoftInputFromWindow(mPasswordEntry.getWindowToken(), 0);
        keyboardVisible = false;
    }

    private boolean isChangePassword() {
        return getIntent().getBooleanExtra(CHANGE_PIN, false);
    }

}
